﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace Jiubang.Collections {
    /// <summary>
    ///   提供对键值对集合线程安全的访问方式。
    ///   由System.Threading.ReadWriteLockSlim类提供线程安全保障。
    /// </summary>
    public sealed class ThreadSafeDict<TKey, TValue> {
        private readonly IDictionary<TKey, TValue> _dict;
        private readonly ReaderWriterLockSlim _lock;

        ///<summary>
        ///  可自定义IDictionary的实现。
        ///</summary>
        ///<param name = "dict">
        ///  封装的键值对集合对象。
        ///  必须注意，该对象在初始化后不应在其他任何地方保留引用。在外部对该对象的操作不受ThreadSafeDict保护。
        ///</param>
        ///<exception cref = "ArgumentNullException"></exception>
        public ThreadSafeDict(IDictionary<TKey, TValue> dict) {
            if (dict == null)
                throw new ArgumentNullException();

            _dict = dict;
            _lock = new ReaderWriterLockSlim();
        }

        /// <summary>
        ///   推荐的初始方式。内部键值对集合的实现可能根据容量自行变化。
        ///   目前统一采用Dictionary实现。
        /// </summary>
        /// <param name = "capacity"> 初始容量 </param>
        /// <param name = "comparer"> 键比较器 </param>
        public ThreadSafeDict(int capacity, IEqualityComparer<TKey> comparer) {
            _dict = new Dictionary<TKey, TValue>(capacity, comparer ?? EqualityComparer<TKey>.Default);
            _lock = new ReaderWriterLockSlim();
        }


        ///<summary>
        ///  使用读锁获取或使用写锁设置某一键所对应的值。
        ///</summary>
        ///<param name = "key">键</param>
        public TValue this[TKey key] {
            get {
                TValue value;
                return TryGetValue(key, out value) ? value : default(TValue);
            }
            set {
                _lock.EnterWriteLock();
                try {
                    _dict[key] = value;
                } finally {
                    _lock.ExitWriteLock();
                }
            }
        }

        /// <summary>
        ///   获取读锁并调用TryGetValue方法
        /// </summary>
        /// <param name = "key"></param>
        /// <param name = "value"></param>
        /// <returns></returns>
        public bool TryGetValue(TKey key, out TValue value) {
            _lock.EnterReadLock();
            try {
                return _dict.TryGetValue(key, out value);
            } finally {
                _lock.ExitReadLock();
            }
        }

        /// <summary>
        ///   获取写锁并尝试从集合中移除指定项
        /// </summary>
        /// <param name = "key"></param>
        /// <returns></returns>
        public bool Remove(TKey key) {
            _lock.EnterWriteLock();
            try {
                return _dict.Remove(key);
            } finally {
                _lock.ExitWriteLock();
            }
        }
    }
}